package com.zdya.combatdocuments.p2pNetwork;


import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zdya.combatdocuments.entity.*;
import com.zdya.combatdocuments.entity.vo.ResultEnum;
import com.zdya.combatdocuments.entity.vo.ResultVo;
import com.zdya.combatdocuments.mapper.*;
import com.zdya.combatdocuments.util.ResultVoUtil;
import com.zdya.combatdocuments.util.WebUtils;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.websocket.OnMessage;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.List;

@Component
@Slf4j
public class P2pService {

    @Autowired
    NodeUtil node;
    @Autowired
    HandleService handleService;
    @Autowired
    NetworkMapper networkMapper;
    @Autowired
    NetworkUserMapper networkUserMapper;
    @Autowired
    GradeMapper gradeMapper;
    @Autowired
    DocApprovalLimitMapper docApprovalLimitMapper;
    @Autowired
    UserMapper userMapper;



    /**
     * type定义
     * 0：向其他节点推送nodeList，以供连接
     * 1:推送文本信息
     * 2：推送图片信息
     * 3：推送文件信息
     * 4：推送文书信息
     * 5：推送群发公告消息
     * 6：向前端推送UserList
     * 7：转发至主节点消息
     * 8：向前端推送用户新增信息
     * 10:区块高度、阶段信息、用户人数、主节点IP信息
     * 11: 主节点同步阶段表+时间限制表
     * 12: 主节点发送表内所有User
     * */


    /**
     * 初始化server服务端
     */
    public void initServer(int port){
        final WebSocketServer socketServer =new WebSocketServer(new
                InetSocketAddress(port) ) {

            @Override
            public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
                log.info("接收到IP地址为：" + webSocket.getRemoteSocketAddress().getAddress().toString() + "的Client连接");//"/127.0.0.1"
                if(node.getIpByWs(webSocket) == "127.0.0.1" || ("127.0.0.1").equals(node.getIpByWs(webSocket))){
                    node.getNodeList().add(new Node(node.getIpByWs(webSocket),webSocket));
                    node.setBrowserClient(webSocket);
                    NodeUtil.client = webSocket;
                    log.info("本机ClientBrowser已保存");
                    //浏览器连接，发送userList
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("type",6);
                    jsonObject.put("content", JSONUtil.toJsonStr(node.getUserList()));
                    node.write(node.client,jsonObject.toString());
                    //浏览器发送 type=10:区块高度、阶段信息、用户人数、主节点IP信息的信息
                    JSONObject content = new JSONObject();
                    content.put("blockHeight",node.blockHeight);
                    content.put("userNum",node.getUserList().size());
                    content.put("primaryIp",node.getPrimaryIp());
                    content.put("stage",node.getGrade());

                    jsonObject.put("type",10);
                    jsonObject.put("content",content);
                    node.write(node.client,jsonObject.toString());
                }else {
                    if(node.getLocalIp() == node.getPrimaryIp() || (node.getLocalIp()).equals(node.getPrimaryIp())){
                        /**主节点发送nodeList*/
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("type",0);
                        jsonObject.put("content", JSONUtil.toJsonStr(node.getNodeList()));
                        node.write(webSocket,jsonObject.toString());
                        log.info("服务端向客户端"+node.getIpByWs(webSocket)+"发送NodeList信息");

                        /**主节点同步阶段表+时间限制表*/
                        JSONObject json = new JSONObject();
                        List<Grade> grades = gradeMapper.selectList(new QueryWrapper<Grade>().eq("network_id", node.getNetworkId()).orderByAsc("create_date"));
                        DocApprovalLimit docApprovalLimit = docApprovalLimitMapper.selectOne(new QueryWrapper<DocApprovalLimit>().eq("network_id", node.getNetworkId()));
                        json.put("type",11);
                        json.put("grades",JSONUtil.toJsonStr(grades));
                        json.put("docApprovalLimit",JSONUtil.toJsonStr(docApprovalLimit));
                        node.write(webSocket,json.toString());
                        log.info("服务端向客户端"+node.getIpByWs(webSocket)+"发送阶段表+时间限制表信息");

                        /**主节点发送链上信息*/
                        JSONObject chainJson = new JSONObject();
                        chainJson.put("type",14);
                        chainJson.put("chainDataList", node.getChainDataList());
                        node.write(webSocket,chainJson.toString());
                        log.info("服务端向客户端"+node.getIpByWs(webSocket)+"同步链上信息");
                    }
                    node.getNodeList().add(new Node(node.getIpByWs(webSocket),webSocket));
//                    //向新链客户端发送自身user
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("type",8);
                    String str = JSONUtil.toJsonStr(node.getLocalUser());
                    User user = JSONUtil.toBean(str, User.class);
                    user.setPrivateKey(null);
                    user.setKeystore(null);
                    jsonObject.put("content", JSONUtil.toJsonStr(user));
                    node.write(webSocket,jsonObject.toString());
                    log.info(node.getLocalIp()+"服务端向客户端"+node.getIpByWs(webSocket)+"发送User信息");
                }
            }

            @Override
            public synchronized void onClose(WebSocket webSocket, int i, String msg, boolean b) {
                //判断来源，浏览器的话 删除并置空，主节点的话，循环关闭置空，其他的remove--list
                String ipByWs = node.getIpByWs(webSocket);
                if(("127.0.0.1").equals(ipByWs)){
                    node.setBrowserClient(null);
                    node.client=null;
                    node.getNodeList().remove(new Node(node.getIpByWs(webSocket),webSocket));
                    log.info("浏览器关闭，关闭连接");
                }else if ((ipByWs).equals(node.getPrimaryIp())) {
                    for (Node node:node.getNodeList()){
                        node.getWebSocket().close();
                    }
                    Network network = networkMapper.selectById(node.getNetworkId());
//                    network.setStatus(1);
                    networkMapper.updateById(network);
                    NetworkUser networkUser = networkUserMapper.selectOne(new QueryWrapper<NetworkUser>().eq("network_id", network.getId()).eq("user_id", node.getLocalUser().getId()));
                    networkUser.setStatus(1);
                    networkUserMapper.updateById(networkUser);
                    node.getNodeList().clear();
                    node.getIdToIpList().clear();
                    node.getUserList().clear();
                    node.getIp_keyList().clear();
                    log.info("主节点关闭，关闭连接");
                }else {
                    node.getNodeList().remove(new Node(node.getIpByWs(webSocket),webSocket));
                    for(User user: node.getUserList()){
                        if (ipByWs == user.getIp() || (ipByWs).equals(user.getIp())){
                            node.getUserList().remove(user);
                            node.getIdToIpList().remove(new IdToIp(ipByWs,user.getId(),webSocket));
                        }
                    }
                    log.info(ipByWs+"节点关闭，关闭连接");
                }
            }
            @Override
            public void onMessage(WebSocket webSocket, String msg) {
                node.threadPool.submit(()->{
                    handleService.handleMessage(webSocket,msg);
                });
            }

            @Override
            @OnMessage(maxMessageSize=5242880)
            public void onMessage(WebSocket webSocket, ByteBuffer msg) {
                node.threadPool.submit(()->{
                    handleService.handleMessage(webSocket,msg);
                });
            }

            @Override
            public void onError(WebSocket webSocket, Exception e) {
                e.printStackTrace();
                node.getNodeList().remove(new Node(node.getIpByWs(webSocket),webSocket));
                node.setBrowserClient(null);
                log.info("connection failed to address:" + webSocket.getRemoteSocketAddress());
            }

            @Override
            public void onStart() {
            }
        };
        socketServer.start();
        log.info("listening websocket p2p port on: " + port);
    }

}
